<?php


namespace api\modules\app\services;


use api\components\Common;
use api\components\DataCenter;
use api\components\GeoService;
use api\components\Request;
use api\models\AreaDict;
use api\modules\app\models\MetaArea;
use api\modules\app\models\Qrcode;
use api\modules\app\models\QrcodeBind;
use api\modules\app\models\QrcodeTag;
use api\modules\app\models\StreetSync;
use api\modules\app\models\TypeSync;
use api\modules\app\models\Unit;
use api\modules\app\models\UnitHistory;
use api\utils\ExportUtil;
use Exception;
use Yii;
use yii\helpers\ArrayHelper;

class UnitService
{
    const CACHE_DATA_KEY = 'translate_code_cache';
    const CACHE_LOCATION_KEY = 'translate_location_cache';
    /** state枚举值定义 部件状态 */
    const STATE_NORMAL = 1; //正常
    const STATE_UNNORMAL = 2; //异常
    const STATE_REPAIRING = 3; //维修中

    /** status枚举值定义 数据状态 */
    const STATUS_DELETE = 0; //已删除
    const STATUS_ENABLED = 1; //正常数据

    /** audit_state枚举值定义 审核状态 */
    const AUDIT_DEFAULT = 0;
    const AUDIT_WAIT = 1;
    const AUDIT_AGREE = 2;
    const AUDIT_REJECT = 3;

    /** has_bind布尔值定义 是否绑定二维码*/
    const BIND_TRUE = 1; //已绑定
    const BIND_FALSE = 0; //未绑定

    /** init_mode枚举值定义 部件编码规则*/
    const INIT_MODE_GRID = 1; //根据网格编码
    const INIT_MODE_META = 2; //根据行政区划编码

    public static function search($params)
    {
        $query = Unit::find();
        $conditions = [];
        if (!empty($params['deploy_id'])) {
            $unitCodes = DeployService::getUnitCodes($params);
            $query->andWhere(['unit_code' => ArrayHelper::getColumn($unitCodes, 'unit_code')]);
        } else {
            $conditions = self::getCondition($params);
        }
        if(!empty($conditions)){
            foreach ($conditions as $con){
                $query->andFilterWhere($con);
            }
        }
        Common::constructPage($query,$params);
        Common::constructSort($query,$params);
        // $query->leftJoin(['qrcode'], 'qrcode.bind_code=unit.unit_code');
//        echo $query->createCommand()->getRawSql();exit;
        $data = $query->asArray()->all();
        $detail = self::calcuRate($query);
        return [
            'count' => $detail['count'],
            'bind' => $detail['bind'],
            'rate' => $detail['rate'],
            'data' => self::transferData($data),
        ];
    }

    public static function searchFromDC($params)
    {
        $params['mile'] = 200;

        $coods = self::fillCood($params);

        //@todo srq
//        $url = 'http://10.89.1.210' . "/united-ciimc-api/v1/generic-query";
//        $url = \Yii::$app->params['es_end_point2'] . "/united-ciimc-api/v1/generic-query";

        $url = DATA_CENTER_HOST . '/united-ciimc-api/v1/generic-query';

        $rParams = [
//            'token' => \Yii::$app->params['es_search_token2'],
            'token' => DATA_CENTER_TOKEN,
            'table' => 'unit',
            'index_type' => 'active',
            'offset' => 0,
            'limit' => 10000,
//            'sorter' => 'geo_distance|lat:' . $coods['lat'] . '|lng:' . $coods['lng'],
            'sorter' => 'geo_distance|lat:' . $params['lat'] . '|lng:' . $params['lng'],
        ];
        $elements = [];
        if(isset($params['name']) && !empty($params['name'])){
            if ($params['name']=='消火栓(专业)') {
                $elements[] = [
                    'type' => 'logicOr',
                    'conditionElements' => [
                        [
                            'type' => 'condition',
                            'value' => 'args.event_type3=消火栓'
                        ],
                        [
                            'type' => 'condition',
                            'value' => 'args.event_type3=消火栓(专业)'
                        ]
                    ],
                ];
            } else {
                $elements[] = [
                    'type' => 'condition',
                    'value' => 'args.event_type3=eq.' . $params['name']
                ];
            }
        }
        if(isset($params['has_bind']) && !empty($params['has_bind'])){
            $elements[] = [
                'type' => 'condition',
                'value' => 'has_bind=eq.' . $params['has_bind']
            ];
        }
        if (isset($params['street_code']) && !empty($params['street_code'])){
            $elements[] = [
                'type' => 'condition',
                'value' => 'town.rawIdentity=eq.' . $params['street_code']
            ];
        } elseif (isset($params['meta_level4']) && !empty($params['meta_level4'])){
            $elements[] = [
                'type' => 'condition',
                'value' => 'town.rawIdentity=eq.' . $params['meta_level4']
            ];
        }
        if(isset($params['grid_code']) && !empty($params['grid_code'])){
            $elements[] = [
                'type' => 'condition',
                'value' => 'gridCode=eq.' . $params['grid_code']
            ];
        }
        if(isset($params['type']) && !empty($params['type'])){
            $elements[] = [
                'type' => 'condition',
                'value' => 'unit_type=eq.' . $params['type']
            ];
        }
        if(isset($params['loc_type_code']) && !empty($params['loc_type_code'])){
            $elements[] = [
                'type' => 'condition',
                'value' => 'loc_type_code=eq.' . $params['loc_type_code']
            ];
        }
        if (isset($params['outer_code']) && !empty($params['outer_code'])) {
            $elements[] = [
                'type' => 'condition',
                'value' => 'code=eq.' . $params['outer_code']
            ];
        }
        if(isset($params['section']) && !empty($params['section']) && isset($params['section_start']) && !empty($params['section_start']) && isset($params['section_end']) && !empty($params['section_end'])){
            $elements[] = [
                'type' => 'condition',
                'value' => 'roadName=eq.' . $params['section']
            ];
            $elements[] = [
                'type' => 'logicOr',
                'conditionElements' => [
                    [
                        'type' => 'logicAnd',
                        'conditionElements' =>[
                            [
                                'type' => 'condition',
                                'value' => 'startRoad=eq.' . $params['section_start']
                            ],
                            [
                                'type' => 'condition',
                                'value' => 'endRoad=eq.' . $params['section_end']
                            ]
                        ]
                    ],
                    [
                        'type' => 'logicAnd',
                        'conditionElements' =>[
                            [
                                'type' => 'condition',
                                'value' => 'startRoad=eq.' . $params['section_end']
                            ],
                            [
                                'type' => 'condition',
                                'value' => 'endRoad=eq.' . $params['section_start']
                            ]
                        ]
                    ]
                ]
            ];
        }

        $elements[] = [
            'type' => 'condition',
            'value' => 'distance=' . $params['lng'] . ',' . $params['lat'] . ',' . $params['mile']
        ];
        $elements[] = [
            'type' => 'condition',
            'value' => 'status=eq.1'
        ];
        // $elements[] = [
        //     'type' => 'condition',
        //     'value' => 'polygon=06014'
        // ];
        $filter = [
            'type' => 'logicAnd',
            'conditionElements' => $elements
        ];
        $rParams['new_filter'] = json_encode($filter,JSON_UNESCAPED_UNICODE);
        Yii::error("======= >>>> ". json_encode($filter));
        $request = new Request();
        $url = $url . '?' . http_build_query($rParams);
        Yii::error("部件查询请求url：". $url);
        $response = $request->request($url, 'GET');
        if ($response) {
            Yii::error("部件查询请求url：". $response);
            $response = json_decode($response, true);
            if (isset($response['result']) && $response['result'] == 'success') {
                $data = $response['data']['messages'];
                $count = $response['data']['numHits'];
                $first = [];
                $final = [];
                if(!empty($data)){
                    foreach ($data as $row){
                        $rowData = [
                            'unit_code' => $row['primeID'],
                            'has_bind' => $row['data']['has_bind'],
                            'lng' => $row['data']['location']['longitude'],
                            'lat' => $row['data']['location']['latitude'],
                            'lng_cd' => $row['data']['coordx'],
                            'lat_cd' => $row['data']['coordy'],
                            'section' => $row['data']['roadName'],
                            'section_start' => $row['data']['startRoad'],
                            'section_end' => $row['data']['endRoad'],
                            'type' => $row['data']['unit_type'],
                            'outer_code' => $row['data']['code'],
                            'loc_type_code' => $row['data']['loc_type_code'],
                            'loc_type_name' => $row['data']['loc_type_name'],
                            'loc_name' => $row['data']['loc_name'],
                        ];

                        $final[] = $rowData;
                        if(empty($first) && $row['data']['has_bind'] == 0){
                            $first = $rowData;
                        }
                    }
                }
                return [
                    'data' => $final,
                    'first' => empty($first) ? new \stdClass() : $first,
                    'count' => $count,
                    'url' => $url,
                    "filter"=> $filter,
                ];
            }
        }
        return false;
    }

    private static function calcuRate($query)
    {
        $total = $query->count();
        $bind = $query->andFilterWhere(['unit.has_bind' => 1])->count();
        $result = [
            'count' => $total,
            'bind' => $bind,
            'rate' => $total == 0 ? "00.00" : (string)round(($bind * 100)/$total,2) . '%'
        ];
        return $result;
    }

    public static function transferData($data)
    {
        $metas = MetaArea::find()->select(['name','code'])->andFilterWhere(['category' => ['区','街道'],'status' => 1])->asArray()->all();
        $metaMaps = ArrayHelper::map($metas,'code','name');
        if ($data['has_bind'] && !empty($data['qrcode'])) {
            $qrcode = Qrcode::findOne(['code' => $data['qrcode']]);
        }
        if(!empty($data)){
            foreach ($data as &$row){
                $row['district_name'] = $row['meta_level3_name'] = $metaMaps[$row['district_code']];
                $row['street_name'] = $row['meta_level4_name'] = $metaMaps[$row['street_code']];
                $row['meta_level5_name'] = $row['community_name'];
                $row['meta_level6_name'] = $row['estate_name'];
                $row['iot_code'] = explode(',', $row['iot_code']);
                $row['meta_level1'] = 'sh01';
                $row['meta_level2'] = 'sh0101';
                $row['meta_level3'] = $row['district_code'];
                $row['meta_level4'] = $row['street_code'];
                $row['meta_level5'] = $row['community_code'];
                $row['meta_level6'] = $row['estate_code'];
                $row['name'] = $row['event_type3'];
                // $row['path'] = $qrcode ? $qrcode->path : '';
            }
        }
        return $data;
    }

    private static function getLog()
    {

    }

    private static function getCondition($params)
    {
        $condition = [];
        if (isset($params['type']) && !empty($params['type'])) {
            $condition[] = ['unit.type' => $params['type']];
        } else {
            $condition[] = ['unit.type' => Unit::TYPE_UNIT];
        }
        if (isset($params['unit_code'])) {
            $condition[] = ['unit.unit_code' => $params['unit_code']];
        }
        if (isset($params['name_code'])) {
            $condition[] = ['unit.name_code' => $params['name_code']];
        }
        if (isset($params['event_type2_code'])) {
            $condition[] = ['unit.event_type2_code' => $params['event_type2_code']];
        }
        if (isset($params['event_type3_code'])) {
            $condition[] = ['unit.event_type3_code' => $params['event_type3_code']];
        }
        if (isset($params['has_bind'])) {
            $condition[] = ['unit.has_bind' => $params['has_bind']];
        }
        if (isset($params['bind_iot'])) {
            $condition[] = ['unit.bind_iot' => $params['bind_iot']];
        }
        if (isset($params['district_code'])) {
            $condition[] = ['unit.district_code' => $params['district_code']];
        }
        if (isset($params['meta_level3'])) {
            $condition[] = ['unit.district_code' => $params['meta_level3']];
        }
        if (isset($params['street_code'])) {
            $condition[] = ['unit.street_code' => $params['street_code']];
        }
        if (isset($params['meta_level4'])) {
            $condition[] = ['unit.street_code' => $params['meta_level4']];
        }
        if (isset($params['community_code'])) {
            $condition[] = ['unit.community_code' => $params['community_code']];
        }
        if (isset($params['meta_level5'])) {
            $condition[] = ['unit.community_code' => $params['meta_level5']];
        }
        if (isset($params['estate_code'])) {
            $condition[] = ['unit.estate_code' => $params['estate_code']];
        }
        if (isset($params['meta_level6'])) {
            $condition[] = ['unit.estate_code' => $params['meta_level6']];
        }
        if (isset($params['grid_code'])) {
            $condition[] = ['unit.grid_code' => $params['grid_code']];
        }
        if (isset($params['state'])) {
            $condition[] = ['unit.state' => $params['state']];
        }
        if (isset($params['audit_state'])) {
            $condition[] = ['unit.audit_state' => $params['audit_state']];
        }
        if (isset($params['cuser'])) {
            $condition[] = ['unit.cuser' => $params['cuser']];
        }
        if (isset($params['section'])) {
            $condition[] = ['section' => $params['section']];
        }
        if (isset($params['section_start'])) {
            $condition[] = ['section_start' => $params['section_start']];
        }
        if (isset($params['section_end'])) {
            $condition[] = ['section_end' => $params['section_end']];
        }
        if (isset($params['dep_code'])) {
            $condition[] = ['dep_code' => $params['dep_code']];
        }
        if (isset($params['status'])) {
            if ($params['status'] != -1) {
                $condition[] = ['unit.status' => $params['status']];
            }
        } else {
            $condition[] = ['unit.status' => self::STATUS_ENABLED];
        }
        if (isset($params['ctime_start'])){
            $condition[] = ['>=','ctime',$params['ctime_start']];
        }
        if (isset($params['ctime_end'])){
            $condition[] = ['<=','ctime',$params['ctime_end']];
        }
        if (isset($params['channel'])) {
            $condition[] = ['channel' => $params['channel']];
        }
        if (isset($params['loc_type_code']) && !empty($params['loc_type_code'])) {
            $condition[] = ['unit.loc_type_code' => $params['loc_type_code']];
        }
        if (isset($params['outer_code']) && !empty($params['outer_code'])) {
            $condition[] = ['unit.outer_code' => $params['outer_code']];
        }
        return $condition;
    }

    public static function view($unitCode)
    {
        $unit = self::getUnit($unitCode);
        $data = $unit->toArray();
        $district = MetaArea::findOne(['code' => $data['district_code']]);
        $street = MetaArea::findOne(['code' => $data['street_code']]);
        $data['district_name'] = $data['meta_level3_name'] = $district->name;
        $data['street_name'] = $data['meta_level4_name'] = $street->name;
        if($data['has_bind'] == 1){
//            $qr = Qrcode::findOne(['bind_code' => $data['unit_code']]);
//            $data['qrcode'] = empty($qr) ? [] : $qr->toArray();

            $data['qrcode'] = ['code'=>$data['qrcode']];
        }
//        if(!empty($data['iot_code'])) {
            if (0) {
            $data['iot_code'] = explode(',', $data['iot_code']);
            if (!empty($data['iot_code'])) {
                $url = DATA_CENTER_HOST . "/united-ciimc-api/v1/generic-query";
                $reqParams = [
                    'table' => 'device',
                    'limit' => 10000,
                    'token' =>  DATA_CENTER_TOKEN,
                    'transform' => '{"total":numHits,"messages":messages}',
                    'filter' => 'exists=eq.true&isVirtual=eq.false&isSensor=eq.true&push_channel=eq.deviceCenter'
                ];
                $reqParams['filter'] .= '&originId=in.,'. implode(',',$data['iot_code']);
                $request = new Request();
                $url = $url . '?' . http_build_query($reqParams);
                Yii::error('感知器列表请求url:'.$url);
                $response = $request->request($url, 'GET');
                Yii::error('感知器列表请求返回:'.$response);
                $response = json_decode($response,true);
                if(isset($response['result']) && $response['result'] == 'success'){
                    $finalData = [];
                    if(!empty($response['data']['messages'])){
                        foreach ($response['data']['messages'] as $row)
                            $finalData[] = [
                                'deviceId' => $row['data']['originId'],
                                'address' => $row['data']['address'],
                                'deviceTypeName' => $row['data']['messageTypeName'],
                                'setUpTime' => $row['data']['setup_time'],
                                'partCode' => isset($row['data']['component_info']['partCode']) ? $row['data']['component_info']['partCode'] : ''
                            ];
                    }
                    $data['iot_info'] = $finalData;
                }else{
                    throw new \Exception('获取感知器数据异常。');
                }
            }
        }
        return $data;
    }

    private static function getUnit($unitCode)
    {
        $unit = Unit::findOne(['id' => $unitCode]);
        if($unit){
            return $unit;
        }else{
            throw new \Exception('此部件不存在。');
        }
    }

    private static function getUnitByCode($unitCode)
    {
        $unit = Unit::findOne(['unit_code' => $unitCode]);
        if($unit){
            return $unit;
        }else{
            throw new \Exception('此部件不存在。');
        }
    }

    public static function create($user,$params)
    {
        //outer_code不能重复
        if (isset($params['outer_code']) && !empty($params['outer_code'])) {
            $unit = Unit::find()->where(['status'=>1,'outer_code'=>$params['outer_code']])->one();
            if (!empty($unit)) {
                throw new \Exception('业务编码已存在');
            }
        }

        $unitCode = self::generateCode($params,UnitService::INIT_MODE_META);
        $coods = self::fillCood($params);
        $trans = Yii::$app->test_3->beginTransaction();
        try {
            $sync = TypeSync::findOne(['name_code' => $params['name_code']]);
            $attributes = [
                'unit_code' => $unitCode,
                'district_code' => $params['district_code'] ?? $params['meta_level3'] ?? '',
                'street_code' => $params['street_code'] ?? $params['meta_level4'] ?? '',
                'community_code' => $params['community_code'] ?? $params['meta_level5'] ?? '',
                'estate_code' => $params['estate_code'] ?? $params['meta_level6'] ?? '',
                'grid_code' => $params['grid_code'],
                'name' => $params['name'] ?? '',
                'name_code' => $params['name_code'] ?? '',
                'event_type1' => $sync->event_type1 ?? '',
                'event_type1_code' => $sync->event_type1_code ?? '',
                'event_type2' => $sync->event_type2 ?? '',
                'event_type2_code' => $sync->event_type2_code ?? '',
                'event_type3' => $sync->event_type3 ?? '',
                'event_type3_code' => $sync->event_type3_code ?? '',
                'images' => implode(',', $params['images']),
                'lat_cd' => $coods['lat_cd'],
                'lng_cd' => $coods['lng_cd'],
                'lat' => $coods['lat'],
                'lng' => $coods['lng'],
                'lng_gcj' => $coods['lng_gcj'],
                'lat_gcj' => $coods['lat_gcj'],
                'address' => $params['address'],
                'section' => $params['section'],
                'dep_code' => $sync->manage_dep ?? '',
                'state' => $params['state'],
                'has_bind' => self::BIND_FALSE,
                'status' => self::STATUS_DELETE,
                'cuser' => $user['id'] ?? 0,
                'cuser_name' => $user['name'] ?? '',
                'ctime' => time(),
                'channel' => 2,
                'audit_state' => 1,
                'bind_iot' => isset($params['iot_code']) && !empty($params['iot_code']) ? 1 : 0,
                'iot_code' => isset($params['iot_code']) && !empty($params['iot_code']) ? implode(',',$params['iot_code']) : '',
                'def' => 1,
                'type' => isset($params['type'])&&!empty($params['type']) ? $params['type'] : 1,

//                'loc_type_name' => isset($params['loc_type_name'])&&!empty($params['loc_type_name']) ? $params['loc_type_name'] : '',
                'outer_code' => isset($params['outer_code'])&&!empty($params['outer_code']) ? $params['outer_code'] : '',
'other_dep' => isset($params['other_dep'])&&!empty($params['other_dep']) ? $params['other_dep'] : '',
            ];
            if (!empty($attributes['community_code'])) {
                $attributes['community_name'] = AreaDict::findOne(['code' => $attributes['community_code']])['name'] ?? '';
            }
            if (!empty($attributes['estate_code'])) {
                $attributes['estate_name'] = AreaDict::findOne(['code' => $attributes['estate_code']])['name'] ?? '';
            }
            if ($attributes['type'] == Unit::TYPE_UNIT) {

            } elseif ($attributes['type'] == Unit::TYPE_LOCATION) {
                $attributes['loc_type_code'] = isset($params['loc_type_code'])&&!empty($params['loc_type_code']) ? $params['loc_type_code'] : '';
                $attributes['loc_type_name'] = Unit::getLocTypeByKey($attributes['loc_type_code']);
                $attributes['loc_name'] = isset($params['loc_name'])&&!empty($params['loc_name']) ? $params['loc_name'] : '';
                $attributes['audit_state'] = 2; //点位直接审核通过
                $attributes['status'] = 1; //点位直接审核通过
            }
            $unit = new Unit($attributes);
            $unit->save();
            /*
            if(isset($params['iot_code']) && !empty($params['iot_code'])){
                $url = IOT_HOST . "/deviceMode/operationDeviceBand";
                $reqParams = [
                    'deviceIds' => $params['iot_code'],
                    'requestType' => 1,
                    'partCode' => $unit->unit_code,
                    'event_type1' => $unit->event_type1,
                    'event_type1_code' => $unit->event_type1_code,
                    'event_type2' => $unit->event_type2,
                    'event_type2_code' => $unit->event_type2_code,
                    'event_type3' => $unit->event_type3,
                    'event_type3_code' => $unit->event_type3_code,
                    'event_name' => $unit->name,
                    'event_name_code' => $unit->name_code,
                ];
                $request = new Request();
                Yii::error('感知器绑定请求url:'.$url);
                $response = $request->rawRequest($url, json_encode($reqParams));
                Yii::error('感知器绑定请求返回:'.$response);
                $response = json_decode($response,true);
                if(isset($response['code']) && $response['code'] == 0){
//                    return true;
                }else{
                    throw new \Exception('获取感知器数据异常。');
                }
            }
            */
            HistoryService::log($unitCode, UnitHistory::TYPE2_INFO_CREATE, $user['username'], ['user_id' => $user['id']]);

            $trans->commit();
            $logService = new LogService();
            $logService->logByUser($user,['module_name'=>'部件','pri_key'=>$unitCode,'sub_type'=>LogService::SUB_TYPE_CREATE,'remark'=>'新增部件']);
            return true;
        }catch (\Exception $e){
            $trans->rollBack();
            throw new \Exception($e->getMessage());
        }
    }

    public static function fillCood($params) {
        $result['lat'] = '';
        $result['lng'] = '';
        $result['lat_gcj'] = '';
        $result['lng_gcj'] = '';
        $result['lat_cd'] = '';
        $result['lng_cd'] = '';

        $dataCenter = new DataCenter();
        if (isset($params['lat_cd']) && isset($params['lng_cd']) && !empty($params['lat_cd'])) {
            $result['lat_cd'] = $params['lat_cd'];
            $result['lng_cd'] = $params['lng_cd'];
            //城地转84
            $response = $dataCenter->coordinateTransform($params['lng_cd'],$params['lat_cd']);
            if (!isset($response['data']) || empty($response['data'])) {
                return $result;
            }
            $result['lat'] = $response['data']['latitude'];
            $result['lng'] = $response['data']['longitude'];
            //84转高德
            $response = $dataCenter->coordinateTransform($result['lng'],$result['lat'],'wgs84','gcj02');
            if (!isset($response['data']) || empty($response['data'])) {
                return $result;
            }
            $result['lat_gcj'] = $response['data']['latitude'];
            $result['lng_gcj'] = $response['data']['longitude'];
            return $result;
        }

        if (isset($params['lat']) && isset($params['lng']) && !empty($params['lat'])) {
            $result['lat'] = $params['lat'];
            $result['lng'] = $params['lng'];
            //84转高德
            $response = $dataCenter->coordinateTransform($params['lng'],$params['lat'],'wgs84','gcj02');
            if (!isset($response['data']) || empty($response['data'])) {
                return $result;
            }
            $result['lat_gcj'] = $response['data']['latitude'];
            $result['lng_gcj'] = $response['data']['longitude'];

            //84转城地
            $response = $dataCenter->coordinateTransform($params['lng'],$params['lat'],'wgs84','shlocal');
            if (!isset($response['data']) || empty($response['data'])) {
                return $result;
            }
            $result['lat_cd'] = $response['data']['latitude'];
            $result['lng_cd'] = $response['data']['longitude'];
            return $result;
        }

        if (isset($params['lat_gcj']) && isset($params['lng_gcj']) && !empty($params['lat_gcj'])) {
            $result['lat_gcj'] = $params['lat_gcj'];
            $result['lng_gcj'] = $params['lng_gcj'];

            //高德转84
            $response = $dataCenter->coordinateTransform($result['lng_gcj'],$result['lat_gcj'],'gcj02','wgs84');
            if (!isset($response['data']) || empty($response['data'])) {
                return $result;
            }
            $result['lat'] = $response['data']['latitude'];
            $result['lng'] = $response['data']['longitude'];
            //84转城地
            $response = $dataCenter->coordinateTransform( $result['lng'],$result['lat'],'wgs84','shlocal');
            if (!isset($response['data']) || empty($response['data'])) {
                return $result;
            }
            $result['lat_cd'] = $response['data']['latitude'];
            $result['lng_cd'] = $response['data']['longitude'];

            return $result;
        }


    }

    //城地转84&高德
    public static function fillCood3($params) {
        $result['lat'] = '';
        $result['lng'] = '';
        $result['lat_gcj'] = '';
        $result['lng_gcj'] = '';
        $result['lat_cd'] = '';
        $result['lng_cd'] = '';

        if (!isset($params['lat_cd']) || !isset($params['lng_cd'])) {
            return $result;
        }

        $result['lat_cd'] = $params['lat_cd'];
        $result['lng_cd'] = $params['lng_cd'];

        $dataCenter = new DataCenter();
        //城地转84
        $response = $dataCenter->coordinateTransform($params['lng_cd'],$params['lat_cd']);
        if (!isset($response['data']) || empty($response['data'])) {
            return $result;
        }

        $result['lat'] = $response['data']['latitude'];
        $result['lng'] = $response['data']['longitude'];

        //84转高德wrong
        $response = $dataCenter->coordinateTransform($params['lng_cd'],$params['lat_cd'],'wgs84','gcj02');
        if (!isset($response['data']) || empty($response['data'])) {
            return $result;
        }
        $result['lat_gcj'] = $response['data']['latitude'];
        $result['lng_gcj'] = $response['data']['longitude'];

        return $result;
    }

    private static function fillCood2($params)
    {
        $result = [];
        $geoService = new GeoService();
        if(isset($params['lat_cd']) && !empty($params['lat_cd']) && isset($params['lng_cd']) && !empty($params['lng_cd'])){
            $result['lat_cd'] = $params['lat_cd'];
            $result['lng_cd'] = $params['lng_cd'];
            list($lng,$lat) = $geoService->cd2gps($params['lng_cd'],$params['lat_cd']);
            $result['lng'] = $lng;
            $result['lat'] = $lat;
        }
        /*if(isset($params['lat']) && !empty($params['lat']) && isset($params['lng']) && !empty($params['lng'])){
            $result['lat'] = $params['lat'];
            $result['lng'] = $params['lng'];
            list($lngCd,$latCd) = $geoService->gps2cd($params['lng'],$params['lat']);
            $result['lng_cd'] = $lngCd;
            $result['lat_cd'] = $latCd;
        }*/
        if (isset($result['lng'])) {
            list($result['lng_gcj'], $result['lat_gcj']) = $geoService->gps2gcj($result['lng'], $result['lat']);
        }
        return $result;
    }

    public static function update($unitCode,$params,$user)
    {
        if (isset($params['outer_code']) && !empty($params['outer_code'])) {
            $unit = Unit::find()->where(['status'=>1,'outer_code'=>$params['outer_code']])->andWhere(['!=','id',$unitCode])->one();
            if (!empty($unit)) {
                throw new \Exception('业务编码已存在');
            }
        }


        $unit = self::getUnit($unitCode);
        $iotCodes = explode(',',$unit->iot_code);
        $coods = self::fillCood($params);
        $trans = Yii::$app->test_3->beginTransaction();
        try {
            $sync = TypeSync::findOne(['name_code' => $params['name_code']]);
            $attributes = [
//                'district_code' => $params['district_code'] ?? $params['meta_level3'] ?? '',
//                'street_code' => $params['street_code'] ?? $params['meta_level4'] ?? '',
//                'community_code' => $params['community_code'] ?? $params['meta_level5'] ?? '',
//                'estate_code' => $params['estate_code'] ?? $params['meta_level6'] ?? '',
                'district_code' => $params['meta_level3'] ?? '',
                'street_code' => $params['meta_level4'] ?? '',
                'community_code' => $params['meta_level5'] ?? '',
                'estate_code' => $params['meta_level6'] ?? '',
                'grid_code' => $params['grid_code'],
                'name' => $params['name'],
                'name_code' => $params['name_code'],
                'event_type1' => $sync->event_type1 ?? '',
                'event_type1_code' => $sync->event_type1_code ?? '',
                'event_type2' => $sync->event_type2 ?? '',
                'event_type2_code' => $sync->event_type2_code ?? '',
                'event_type3' => $sync->event_type3 ?? '',
                'event_type3_code' => $sync->event_type3_code ?? '',
                'images' => implode(',', $params['images']),
                'lat_cd' => $coods['lat_cd'],
                'lng_cd' => $coods['lng_cd'],
                'lat' => $coods['lat'],
                'lng' => $coods['lng'],
                'lng_gcj' => $coods['lng_gcj'],
                'lat_gcj' => $coods['lat_gcj'],
                'address' => $params['address'],
                'section' => $params['section'],
                'dep_code' => $sync->manage_dep ?? '',
                'state' => $params['state'],
                'bind_iot' => isset($params['iot_code']) && !empty($params['iot_code']) ? 1 : 0,
                'iot_code' => isset($params['iot_code']) && !empty($params['iot_code']) ? implode(',',$params['iot_code']) : '',
                'def' => $params['def'],
                'outer_code' => isset($params['outer_code'])&&!empty($params['outer_code']) ? $params['outer_code'] : '',
 'other_dep' => isset($params['other_dep'])&&!empty($params['other_dep']) ? $params['other_dep'] : '',
            ];

            if ($unit->type == Unit::TYPE_UNIT) {

            } elseif ($unit->type == Unit::TYPE_LOCATION) {
                $attributes['loc_type_code'] = isset($params['loc_type_code'])&&!empty($params['loc_type_code']) ? $params['loc_type_code'] : '';
                $attributes['loc_type_name'] = Unit::getLocTypeByKey($attributes['loc_type_code']);
                $attributes['loc_name'] = isset($params['loc_name'])&&!empty($params['loc_name']) ? $params['loc_name'] : '';
            }

            $unit->setAttributes($attributes);
            $unit->save();
            /*
            $delCodes = [];
            $addCodes = [];
            if(isset($params['iot_code'])){
                foreach ($params['iot_code'] as $iot){
                    if(!in_array($iot,$iotCodes)){
                        $addCodes[] = $iot;
                    }
                }
                if(!empty($iotCodes)){
                    foreach ($iotCodes as $iot){
                        if(!in_array($iot,$params['iot_code'])){
                            $delCodes[] = $iot;
                        }
                    }
                }
            }else{
                if(!empty($iotCodes)){
                    $delCodes = $iotCodes;
                }
            }
            $url = IOT_HOST . "/deviceMode/operationDeviceBand";
            $reqParams = [
                'partCode' => $unit->unit_code,
            ];
            if(!empty($addCodes)){
                $reqParams = array_merge($reqParams, [
                    'requestType' => 1,
                    'deviceIds' => $addCodes,
                    'event_type1' => $unit->event_type1,
                    'event_type1_code' => $unit->event_type1_code,
                    'event_type2' => $unit->event_type2,
                    'event_type2_code' => $unit->event_type2_code,
                    'event_type3' => $unit->event_type3,
                    'event_type3_code' => $unit->event_type3_code,
                    'event_name' => $unit->name,
                    'event_name_code' => $unit->name_code,
                ]);
                $request = new Request();
                Yii::error('感知器绑定请求url:'.$url);
                $response = $request->rawRequest($url, json_encode($reqParams));
                Yii::error('感知器绑定请求返回:'.$response);
                $response = json_decode($response,true);
                if(isset($response['code']) && $response['code'] == 0){
//                    return true;
                }else{
                    throw new \Exception('获取感知器数据异常。');
                }
            }
            if(!empty($delCodes)){
                $reqParams['requestType'] = 2;
                $reqParams['deviceIds'] = $delCodes;
                $request = new Request();
                Yii::error('感知器绑定请求url:'.$url);
                $response = $request->rawRequest($url, json_encode($reqParams));
                Yii::error('感知器绑定请求返回:'.$response);
                $response = json_decode($response,true);
                if(isset($response['code']) && $response['code'] == 0){
//                    return true;
                }else{
                    throw new \Exception('获取感知器数据异常。');
                }
            }
            */
            HistoryService::log($unitCode, UnitHistory::TYPE2_INFO_UPDATE, $user['username'], ['user_id' => $user['id']]);

            $trans->commit();
            $logService = new LogService();
            $logService->logByUser($user,['module_name'=>'部件','pri_key'=>$unit->unit_code,'sub_type'=>LogService::SUB_TYPE_UPDATE,'remark'=>'编辑部件']);
            return $unit;
        }catch (\Exception $e){
            $trans->rollBack();
            throw new \Exception($e->getMessage());
        }
    }

    public static function delete($user, $unitCode)
    {
        $trans = Yii::$app->test_3->beginTransaction();
        try {
            $unit = self::getUnit($unitCode);
            if ($unit->has_bind) {
                throw new Exception('请先解除二维码绑定');
            }
            $unit->setAttribute('status', self::STATUS_DELETE);
            self::unbindIot($unit);
            $unit->iot_code = '';
            $unit->save();
            $trans->commit();

            $logService = new LogService();
            $logService->logByUser($user,['module_name'=>'部件','pri_key'=>$unit->unit_code,'sub_type'=>LogService::SUB_TYPE_DELETE,'remark'=>'删除部件']);

            return true;
        }catch (\Exception $e){
            $trans->rollBack();
            throw new \Exception($e->getMessage());
        }
    }

    private static function unbindIot(Unit $unit)
    {
        $codes = empty($unit->iot_code) ? [] : explode(',', $unit->iot_code);
        if (empty($codes)) {
            return true;
        }
        $url = IOT_HOST . "/deviceMode/operationDeviceBand";
        $reqParams = [
            'partCode' => $unit->unit_code,
            'requestType' => 2,
            'deviceIds' => $codes,
        ];

        $request = new Request();
        Yii::error('感知器绑定请求url:' . $url);
        $response = $request->rawRequest($url, json_encode($reqParams));
        Yii::error('感知器绑定请求返回:'.$response);
        $response = json_decode($response,true);
        if(isset($response['code']) && $response['code'] == 0){
            return true;
        } else {
            throw new \Exception('解除绑定感知器异常。');
        }
    }

    public static function audit($params)
    {
        $unitCode = $params['unit_code'];
        $trans = Yii::$app->test_3->beginTransaction();
        try {
            $unit = self::getUnitByCode($unitCode);
            $attributes = [
                'audit_state' => $params['audit_state'],
                'audit_time' => time()
            ];
            if($params['audit_state'] == 2){
                $attributes['status'] = self::STATUS_ENABLED;
            }
            $unit->setAttributes($attributes);
            $unit->save();
            $trans->commit();
            return true;
        }catch (\Exception $e){
            $trans->rollBack();
            throw new \Exception($e->getMessage());
        }
    }

    public static function unbind2($unitCode)
    {
        $trans = Yii::$app->test_3->beginTransaction();
        try {
            $unit = self::getUnitByCode($unitCode);
            $unit->has_bind = self::BIND_FALSE;
            $unit->qrcode = '';
            $unit->save();
            $trans->commit();
        }catch (\Exception $e){
            $trans->rollBack();
            throw new \Exception($e->getMessage());
        }
        QrcodeService::unbind($unitCode);
        return true;
    }

    public static function unbind($unitCode)
    {
        $trans = Yii::$app->test_3->beginTransaction();
        try {
            $unit = self::getUnitByCode($unitCode);
            $qrcode = $unit->qrcode;
            if (!empty($qrcode)) {
                QrcodeService::syncHasBind($unit->qrcode);
            }

            $unit->has_bind = self::BIND_FALSE;
            $unit->qrcode = '';
            $unit->save();

            $qrcodeBind = QrcodeBind::find()->where(['unit_code'=>$unitCode,'is_delete'=>0])->one();
            if (!empty($qrcodeBind)) {
                $qrcodeBind->is_delete = 1;
                $qrcodeBind->save();
            }

            $trans->commit();
        }catch (\Exception $e){
            $trans->rollBack();
            throw new \Exception($e->getMessage());
        }

        return true;
    }

    /**
     * @param $params
     * @param $mode 1:根据网格编码，2：根据区街道编码
     * @return string
     * @throws Exception
     */
    public static function generateCode($params, $mode = self::INIT_MODE_GRID)
    {
        $redis = Yii::$app->redis;

        if (isset($params['type']) && $params['type'] == Unit::TYPE_LOCATION) {
            //点位
            $type = 'DWLX**';
        } else {
            $type = $params['name_code'];
            $typeSync = TypeSync::findOne(['name_code' => $type]);
            if(!$typeSync){
                throw new \Exception('部件类型编码未定义。');
            }
            $type = $typeSync->sync_code;
        }

        $district_code = $params['district_code'];
        if($mode == self::INIT_MODE_META) {
            if (isset($params['street_code']) && !empty($params['street_code'])) {
                $street_code = $params['street_code'];
                $streetSync = StreetSync::findOne(['street_code' => $street_code]);
                if (!$streetSync) {
                    $street_code = 'TEST';
                } else {
                    $street_code = $streetSync->sync_code;
                }
            } else {
                $street_code = $district_code . '00';
            }
        }elseif ($mode == self::INIT_MODE_GRID){
            $street_code = $params['polygon'];
        }else{
            throw new \Exception('编码模式未定义。');
        }
        $event_id = $redis->incr($type . $street_code);
        if ($event_id == 0) {
            $event_id = $redis->incr($type . $street_code);
        }
        //$code = $street_code . str_pad($type,6,'*',STR_PAD_RIGHT) . sprintf('%06s', strval($event_id));
        $code = $district_code . $street_code . $type . sprintf('%06s', strval($event_id));
        return strval($code);
    }

    public static function export($params)
    {
$districtMap = MetaArea::find()->select(['name'])->where(['category' => '区'])->indexBy('code')->column();
        $params['type'] = Unit::TYPE_UNIT;
        $conditions = self::getCondition($params);
        foreach ($conditions as $condition) {
            $query = Unit::find()->andFilterWhere($condition);
        }
                $title = '标识码,部件名称,一级分类,二级分类,管理部门,部件位置,所属区域,是否绑码,部件状态,二级管理部门,部件编码,经度,纬度,码值,新行业管理编码,全市唯一编码';
        $header = explode(',', $title);
        $rows = [];
        $cacheData = Yii::$app->redisCache->get(self::CACHE_DATA_KEY);
        empty($cacheData) && $cacheData = [];
// $qrcodeBind = QrcodeBind::find()->select(['unit_code','qrcode'])->where(['is_delete'=>0,'type'=>Unit::TYPE_UNIT])->indexBy('unit_code')->asArray()->all();
        foreach ($query->each() as $item) {
$qrcodeBind = QrcodeBind::find()->select(['unit_code','qrcode'])->where(['is_delete'=>0,'unit_code'=>$item['unit_code']])->asArray()->one();
            $qrcode = !empty($qrcodeBind) ? $qrcodeBind['qrcode'] : '';
            $rows[] = [
                'id' => chr(0x1E) . $item['unit_code'],
                'unitName' => $item['name'],
                'eventType2' => $item['event_type2'],
                'eventType3' => $item['event_type3'],
                'dep' => $item['dep_code'],
                'address' => $item['address'],
                //'district' => self::translateCode($cacheData, $item),
 'district' => isset($districtMap[$item['district_code']])?$districtMap[$item['district_code']]:'',
    'hasBind' => $qrcode ? '是' : '否',
                'state' => $item['state'] == 1 ? '正常' : '异常',
                'other_dep' => $item['other_dep'],
                'outer_code' => $item['outer_code'],
 'lng' => $item['lng'],
                'lat' => $item['lat'],
                'url' => !empty($qrcode) ? "https://jacode.iotsh.com.cn:18081/ja/code/index.html?code={$qrcode}" : '',
                'industry_code' => $item['industry_code'],
                'city_unique_code' => $item['city_unique_code'],
            ];
        }
        $filename = 'export_' . date('Y-m-d') . '_' . uniqid() . '.csv';
        $file = ExportUtil::exportCsv($filename, $header, $rows);
        $localPath = '/exportfile/'.date('Y-m-d').'/'.$filename;
        return ['url' => $localPath];

//        $file = ExportUtil::exportCsv($filename, $header, $rows);
//        if (YII_ENV == 'prod' || YII_ENV == 'uat') {
//            $response = Yii::$app->fileServer->uploadFile($file);
//            @unlink($file->getRealPath());
//        }
//
//        return [
//            'url' => $response['path'] ?? "exportfile/${filename}",
//        ];
    }

    public static function exportLocation() {
        $params['type'] = Unit::TYPE_LOCATION;
        $result = self::search($params);
        $data = $result['data'];
        $header = ['标识码','点位名称','点位类型','所属区域','位置','业务编码','是否绑码','二级管理部门','部件编码'];
        $rows = [];
        foreach ($data as $item) {
            $areaArr[] = $item['meta_level3_name'];
            $areaArr[] = $item['meta_level4_name'];
            $rows[] = [
                chr(0x1E) . $item['unit_code'],
                $item['loc_name'],
                $item['loc_type_name'],
                implode('/',$areaArr),
                $item['address'],
                $item['outer_code'],
                $item['has_bind'] ? '是' : '否',
                $item['other_dep'],
                $item['outer_code'],
            ];
        }

//        $conditions = self::getCondition($params);
//        foreach ($conditions as $condition) {
//            $query = Unit::find()->andFilterWhere($condition);
//        }
//        $header = ['标识码','点位名称','点位类型','所属区域','位置','业务编码','是否绑码'];
//        $rows = [];
//        $cacheData = Yii::$app->redisCache->get(self::CACHE_LOCATION_KEY);
//        empty($cacheData) && $cacheData = [];
//        foreach ($query->each() as $item) {
//
//        }

        $filename = 'export_' . date('Y-m-d') . '_' . uniqid() . '.csv';
        $file = ExportUtil::exportCsv($filename, $header, $rows);
        $localPath = '/exportfile/'.date('Y-m-d').'/'.$filename;
        return ['url' => $localPath];
    }

    private static function translateCode(&$cacheData, $item)
    {
        $districtCode = $item['district_code'] ?? 0;
        $streetCode = $item['street_code'] ?? 0;
        $gridCode = $item['grid_code'] ?? 0;
        if (empty($cacheData)) {
            $district = MetaArea::findOne(['code' => $districtCode]);
            $cacheData[$districtCode] = $district->name;
            $streets = MetaArea::findAll(['parent_id' => $districtCode, 'category' => '街道']);
            foreach ($streets as $street) {
                $cacheData[$street->code] = $street->name;
                $grids = MetaArea::findAll(['parent_id' => $street->code, 'category' => '网格']);
                foreach ($grids as $grid) {
                    $cacheData[$grid->code] = $grid->name;
                }
            }

            Yii::$app->redisCache->set(self::CACHE_DATA_KEY, $cacheData);
        }
        $value = $cacheData[$districtCode];
        if (!empty($cacheData[$streetCode])) {
            $value = $value . '/' . $cacheData[$streetCode];
        }
        if (!empty($cacheData[$gridCode])) {
            $value = $value . '/' . $cacheData[$gridCode];
        }

        return $value;
    }

    public static function translateToGcj()
    {
        $count = 0;
        $query = Unit::find();
        foreach ($query->each() as $unit) {
            if (!isset($unit['lng'])) {
                continue;
            }
            $count++;
            list($lng_gcj, $lat_gcj) = (new GeoService())->gps2gcj($unit['lng'], $unit['lat']);
            Unit::updateAll(['lng_gcj' => $lng_gcj, 'lat_gcj' => $lat_gcj], ['unit_code' => $unit['unit_code']]);
        }

        return $count;
    }

    public static function batchTag($params)
    {
        Unit::updateAll(['def' => $params['def']],['name_code' => $params['name_code']]);
        return true;
    }

    public static function delIotLinks($iotCode)
    {
        $trans = Yii::$app->test_3->beginTransaction();
        try {
            $units = Unit::find()->andFilterWhere(['like','iot_code',$iotCode])->all();
            if(!empty($units)){
                foreach ($units as $obj){
                    $souceIot = explode(',',$obj->iot_code);
                    unset($souceIot[array_search($iotCode,$souceIot)]);
                    $attrs = [
                        'iot_code' => empty($souceIot) ? '' : implode(',', $souceIot),
                        'bind_iot' => empty($souceIot) ? 0 : 1
                    ];
                    $obj->setAttributes($attrs);
                    $obj->save();
                }
            }
            $trans->commit();
            return true;
        } catch (\Exception $e) {
            $trans->rollBack();
            throw new \Exception($e->getMessage());
        }
        return true;
    }
}
